﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text.RegularExpressions;
using Crawler.ApplicationServices;
using Crawler.Domain.DataEntities;
using Crawler.Domain.DataEntities.Crawling;
using Crawler.Domain.Sources;
using Crawler.DomainServices.DataServices;
using Crawler.DomainServices.Processors;
using HtmlAgilityPack;
using log4net;
using StructureMap;

namespace Crawler.DomainServices.Pages
{
	public class YifyTorrentFileLinkPage
	{
		private readonly string _sessionId;
		private readonly YifyMoviePage _page;
		private readonly ISourceContentRepository _repository;
		private readonly IHtmlParserHelper _parserHelper;
		private IRequestsHelper _requestsHelper;
		private static readonly ILog Logger=LogManager.GetLogger("AppLogger");

		public YifyTorrentFileLinkPage(string sessionId, YifyMoviePage page)
		{
			_sessionId = sessionId;
			_page = page;

			this._repository = ObjectFactory.GetInstance<ISourceContentRepository>();
			_parserHelper = ObjectFactory.GetInstance<IHtmlParserHelper>();
			_requestsHelper = ObjectFactory.GetInstance<IRequestsHelper>();
		}

		public IList<string> GetTorrentFileUrls()
		{
			string url = string.Format(@"http://www.yify-torrent.org/download/torrent-{0}.html", _page.IdInSource);
			RawPageCrawlInfo rawPage = _repository.GetProccessableContentByUrl(_sessionId, url);
			string txt;

			if (rawPage == null)
			{
				txt=_requestsHelper.GetPageHtmlText(url);
			}
			else
			{
				string filePath = rawPage.FilePath;
				txt = File.ReadAllText(filePath);
			}
			if (string.IsNullOrEmpty(txt))
			{
				Logger.WarnFormat("GetTorrentFileUrls - Could not retrieve any data Session:{0} - url: {1}",_sessionId,url);
				return new string[0];
			}

			var d = new HtmlDocument();
			d.LoadHtml(txt);

			HtmlNodeCollection nodes = d.DocumentNode.SelectNodes(@"//div[@class='span-4']");

			return new[]
			{_parserHelper.GetAttributeValueOfSingleNode(nodes[0], @"//a[1]", "href"),
				_parserHelper.GetAttributeValueOfSingleNode(nodes[1], @"//a[1]", "href")
			};
		}
	}
	
	public class YifyMoviePage
	{
		private const string mdescPartSelector =
			@"/html[1]/body[1]/div[@id='shell']/div[@class='moviebody']/div[@class='minfo']/div[@class='mdesc']";

		private readonly IHtmlParserHelper _htmlParserHelper;
		private int _durationMinutes = int.MinValue;
		private string _fileFormat;
		private string _frameRate;
		private string _language;
		private string _magnetUrl;
		private int _peers = int.MinValue;
		private string _qualityCategory;
		private string _resolution;
		private int _seeds = int.MinValue;
		private string _title;
		private int _year = int.MinValue;
		private string _imdbUrl;
		private string _mpr;

		private YifyMoviePage(MovieProcessableSource source)
		{
			_htmlParserHelper = ObjectFactory.GetInstance<IHtmlParserHelper>();

			IdInSource = source.IdInSource;
			Document = new HtmlDocument();
			Document.LoadHtml(source.Text);
		}

		private HtmlDocument Document { get; set; }

		public string IdInSource { get; private set; }

		public string MagnetUrl
		{
			get
			{
				return _magnetUrl ?? (_magnetUrl = _htmlParserHelper.GetAttributeValueOfSingleNode(Document.DocumentNode,
					string.Concat(mdescPartSelector, @"/div[@class='outattr']/div[3]/a[1]"), "href"));
			}
		}

		public int Seeds
		{
			get
			{
				if (_seeds == int.MinValue)
				{
					ParseInAttrPart();
				}
				return _seeds;
			}
		}

		public int Peers
		{
			get
			{
				if (_peers == int.MinValue)
				{
					ParseInAttrPart();
				}
				return _peers;
			}
		}

		public int DurationMinutes
		{
			get
			{
				if (_durationMinutes == int.MinValue)
				{
					ParseInAttrPart();
				}
				return _durationMinutes;
			}
		}

		public string Language
		{
			get
			{
				if (_language == null)
				{
					ParseInAttrPart();
				}
				return _language;
			}
		}

		public string FrameRate
		{
			get
			{
				if (_frameRate == null)
				{
					ParseInAttrPart();
				}
				return _frameRate;
			}
		}

		public string Resolution
		{
			get
			{
				if (_resolution == null)
				{
					ParseInAttrPart();
				}
				return _resolution;
			}
		}


		public string ImdbUrl
		{
			get
			{
				if (_imdbUrl == null)
				{
					ParseInAttrPart();
				}
				return _imdbUrl;
			}
		}

		public string MPR
		{
			get
			{
				if (_mpr == null)
				{
					ParseInAttrPart();
				}
				return _mpr;
			}
		}

		public string FileFormat
		{
			get
			{
				if (_fileFormat == null)
				{
					ParseTitlePart();
				}
				return _fileFormat;
			}
		}

		public string QualityCategory
		{
			get
			{
				if (_qualityCategory == null)
				{
					ParseInAttrPart();
				}
				return _qualityCategory;
			}
		}

		public string Title
		{
			get
			{
				if (_title == null)
				{
					ParseTitlePart();
				}
				return _title;
			}
		}

		public int Year
		{
			get
			{
				if (_year == int.MinValue)
				{
					ParseTitlePart();
				}
				return _year;
			}
		}


		public static YifyMoviePage FromHtml(MovieProcessableSource source)
		{
			return new YifyMoviePage( source);
		}


		

		private void ParseInAttrPart()
		{
			HtmlNodeCollection src =
				Document.DocumentNode.SelectNodes(string.Concat(mdescPartSelector, @"/div[@class='inattr']/ul/li"));

			_resolution =
				src.Single(x => x.InnerText.StartsWith("Resolution:")).InnerText.Remove(0, "Resolution:".Length).Trim();

			_qualityCategory =
				src.Single(x => x.InnerText.StartsWith("Quality:")).InnerText.Remove(0, "Quality:".Length).Trim();
			_frameRate =
				src.Single(x => x.InnerText.StartsWith("Frame Rate:")).InnerText.Remove(0, "Frame Rate:".Length).Trim();
			_language =
				src.Single(x => x.InnerText.StartsWith("Language:")).InnerText.Remove(0, "Language:".Length).Trim();
			_durationMinutes =
				int.Parse(src.Single(x => x.InnerText.StartsWith("Run Time:")).InnerText.Remove(0, "Run Time:".Length).Trim());
			
			_mpr = src.Single(x => x.InnerText.StartsWith("MPR:")).InnerText.Remove(0, "MPR:".Length).Trim();

			string ps =
				src.Single(x => x.InnerText.StartsWith(@"Peers/Seeds:")).InnerText.Remove(0, @"Peers/Seeds:".Length).Trim();
			_peers = int.Parse(ps.Split('/')[0]);
			_seeds = int.Parse(ps.Split('/')[1]);
			_imdbUrl =
				Document.DocumentNode.SelectNodes(string.Concat(mdescPartSelector, @"/div[@class='inattr']/ul/li/a/@href"))
					.Single(
						x => x.HasAttributes && x.Attributes.Any(y => y.Name == "href" && y.Value.StartsWith("http://www.imdb.com/title")))
					.Attributes[0].Value;


		}

		private void ParseTitlePart()
		{
			HtmlNode src = Document.DocumentNode.SelectSingleNode(string.Concat(mdescPartSelector, @"/div[@class='name']"));

			Match m = Regex.Match(src.InnerText, @"\((\d+)\).*?");

			if (!m.Success)
				throw new InvalidDataException();

			_year = int.Parse(m.Groups[1].Value);
			string[] strings = src.InnerText.Split(new[] {string.Format("({0})", Year)}, StringSplitOptions.None);
			_title = strings[0].Trim();
			strings = strings[1].Trim().Split(' ');
			_fileFormat = strings.Length == 2 ? strings[1].Trim() : strings[0].Trim();
		}

		
	}
}